﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using MyFramework.Web.Api;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;

namespace MyFramework.Plugins.Core.Core
{
    /// <summary>
    /// 
    /// </summary>
    public class CompileAssemblyHelper
    {
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static void CompileAssembly(string pluginName)
        {
            var dllPath = Path.Combine(MyPluginPathProvider.Plugins, pluginName, $"{pluginName}.dll");
            if (!Directory.Exists(Path.GetDirectoryName(dllPath)))
                Directory.CreateDirectory(Path.GetDirectoryName(dllPath));
            if (File.Exists(dllPath))
            {
                File.Delete($"{dllPath}.old");
                File.Move(dllPath, $"{dllPath}.old");
            }


            var sourceFiles = Directory.EnumerateFiles(
                MyPluginPathProvider.SourceCode, "*.cs", SearchOption.AllDirectories);
            var compilationOptions = new CSharpCompilationOptions(
                OutputKind.DynamicallyLinkedLibrary,
                optimizationLevel: OptimizationLevel.Debug);


            var _defaultAssemblies = AssemblyLoadContext.Default.Assemblies
                .Where(assembly => !assembly.IsDynamic)
                .ToList();
            var references = _defaultAssemblies
                .Select(assembly => assembly.Location)
                .Where(path => !string.IsNullOrEmpty(path) && File.Exists(path))
                .Select(path => MetadataReference.CreateFromFile(path))
                .ToList();
            var syntaxTrees = sourceFiles
                .Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p)))
                .ToList();
            var compilation = CSharpCompilation.Create(pluginName)
                .WithOptions(compilationOptions)
                .AddReferences(references)
                .AddSyntaxTrees(syntaxTrees);
            var emitResult = compilation.Emit(dllPath);
            if (!emitResult.Success)
            {
                throw new InvalidOperationException(string.Join("\r\n",
                    emitResult.Diagnostics.Where(d => d.WarningLevel == 0)));
            }
        }
        /// <summary>
        /// 编译代码片段
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="outputPath">dll输出路径</param>
        /// <param name="xmlDocumentationPath">xml输出路径</param>
        /// <param name="sourceCodes"></param>
        public static void CompileAssembly(string assemblyName, string outputPath, string xmlDocumentationPath, List<string> sourceCodes)
        {
            var sourceFiles = Directory.EnumerateFiles(
                MyPluginPathProvider.SourceCode, "*.cs", SearchOption.AllDirectories);
            var compilationOptions = new CSharpCompilationOptions(
                OutputKind.DynamicallyLinkedLibrary,
                optimizationLevel: OptimizationLevel.Debug);


            var _defaultAssemblies = AssemblyLoadContext.Default.Assemblies
                .Where(assembly => !assembly.IsDynamic)
                .ToList();
            var references = _defaultAssemblies
                .Select(assembly => assembly.Location)
                .Where(path => !string.IsNullOrEmpty(path) && File.Exists(path))
                .Select(path => MetadataReference.CreateFromFile(path))
                .ToList();
            //var syntaxTrees = sourceFiles
            //    .Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p)))
            //    .ToList();
            List<SyntaxTree> syntaxTrees = new List<SyntaxTree>();
            var listSourceCode = sourceCodes.GetEnumerator();
            while (listSourceCode.MoveNext())
            {
                string sourceCode = listSourceCode.Current;
                syntaxTrees.Add(CSharpSyntaxTree.ParseText(sourceCode));
            }
            var compilation = CSharpCompilation.Create(assemblyName)
                .WithOptions(compilationOptions)
                .AddReferences(references)
                .AddSyntaxTrees(syntaxTrees);
            var emitResult = compilation.Emit(outputPath: outputPath, xmlDocumentationPath: xmlDocumentationPath);
            if (!emitResult.Success)
            {
                throw new InvalidOperationException(string.Join("\r\n",
                    emitResult.Diagnostics.Where(d => d.WarningLevel == 0)));
            }
        }
    }
}
